package multidimensional;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashSet;

import data.DistancedPoints;
import data.TableDistances;

import util.Util;
import Graph.Graph;
import Graph.GraphDrawer;

public class SpringEmbedder extends Embedder2D {

    double maxStep = 0.01;
    double k = 0.001;
    DistancedPoints points;
    private double maxRealDist;

    public SpringEmbedder(DistancedPoints t) {
        super(t);
        points = t;

        maxRealDist = 1;
    }

    public void iteration() {

//        for (int i = 0; i < points.getCount(); i++) {
//            double x = getX(i);
//            double y = getY(i);
//
//            setX(i, x + Math.random() - 0.5);
//            setY(i, y + Math.random() - 0.5);
//        }

        // for your implementation do this:

        //init force-vectors to (0,0) for all nodes
        double dsp_x[] = new double[points.getCount()];
        double dsp_y[] = new double[points.getCount()];

        for (int i = 0; i < points.getCount(); i++) {
            dsp_x[i] = 0;
            dsp_y[i] = 0;

        }

        //compute spring forces and add them to the force vectors

        for (int i = 0; i < points.getCount() - 1; i++) {          

            for (int j = i+1; j < points.getCount(); j++) {
                double x1 = getX(i);
                double y1 = getY(i);

                double x2 = getX(j);
                double y2 = getY(j);


                maxRealDist = points.getDistance(i, j);

                double edge_dist = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

                if (edge_dist > maxRealDist) { //if the edge distance is more than the real distance

                    double deltaX = x2 - x1;
                    double deltaY = y2 - y1;


                    dsp_x[i] = dsp_x[i] + (deltaX / edge_dist) * fa(edge_dist);
                    dsp_y[i] = dsp_y[i] + (deltaY / edge_dist) * fa(edge_dist);
                    dsp_x[j] = dsp_x[j] - (deltaX / edge_dist) * fa(edge_dist);
                    dsp_y[j] = dsp_y[j] - (deltaY / edge_dist) * fa(edge_dist);
                }

            }
        }

        //add forces to current positions of the nodes (getX, getY will give you the current positions).        
        for (int i = 0; i < points.getCount(); i++) {

            double dist = Math.sqrt(dsp_x[i] * dsp_x[i] + dsp_y[i] * dsp_y[i]);

            double newX = (dsp_x[i] / dist) * Math.min(dist, maxStep);
            double newY = (dsp_y[i] / dist) * Math.min(dist, maxStep);

            setX(i, getX(i) + (int) newX);
            setY(i, getY(i) + (int) newY);

        }
        
        //cool down system (max_step)
         maxStep = Math.max(0.001,maxStep * 0.90);
    }

    public double fa(double z) {
        return ((z * z) / k);
    }

  
}